package com.djf.djfcs.esService;

import com.djf.djfcs.entity.es.OrderDocument;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 订单Elasticsearch服务
 * 提供订单文档的增删改查功能
 */
@Slf4j
@Service
public class OrderEsService {

    private final RestHighLevelClient esClient;
    private final ObjectMapper objectMapper;
    private static final String INDEX_NAME = "orders";

    @Autowired
    public OrderEsService(RestHighLevelClient esClient, ObjectMapper objectMapper) {
        this.esClient = esClient;
        this.objectMapper = objectMapper;
    }

    /**
     * 创建订单索引及映射
     * @return 是否创建成功
     * @throws IOException IO异常
     */
    public boolean createOrderIndex() throws IOException {
        // 检查索引是否存在
        GetIndexRequest request = new GetIndexRequest(INDEX_NAME);
        boolean exists = esClient.indices().exists(request, RequestOptions.DEFAULT);
        if (exists) {
            log.info("订单索引 '{}' 已存在", INDEX_NAME);
            return false;
        }

        // 构建创建索引请求
        CreateIndexRequest createRequest = new CreateIndexRequest(INDEX_NAME);
        createRequest.settings(Settings.builder()
                .put("index.number_of_shards", 1)
                .put("index.number_of_replicas", 0)
        );

        // 定义订单索引映射
        createRequest.mapping(
                "{\n" +
                        "  \"properties\": {\n" +
                        "    \"id\": { \"type\": \"long\" },\n" +
                        "    \"orderNo\": { \"type\": \"keyword\" },\n" +
                        "    \"tenantId\": { \"type\": \"keyword\" },\n" +
                        "    \"userId\": { \"type\": \"long\" },\n" +
                        "    \"productName\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\" },\n" +
                        "    \"totalAmount\": { \"type\": \"double\" },\n" +
                        "    \"status\": { \"type\": \"keyword\" },\n" +
                        "    \"remark\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\" },\n" +
                        "    \"createTime\": { \"type\": \"date\", \"format\": \"yyyy-MM-dd'T'HH:mm:ss\" },\n" +
                        "    \"updateTime\": { \"type\": \"date\", \"format\": \"yyyy-MM-dd'T'HH:mm:ss\" },\n" +
                        "    \"syncTimestamp\": { \"type\": \"long\" },\n" +
                        "    \"operationType\": { \"type\": \"keyword\" }\n" +
                        "  }\n" +
                        "}",
                XContentType.JSON
        );

        // 执行创建索引操作
        AcknowledgedResponse createIndexResponse = esClient.indices().create(createRequest, RequestOptions.DEFAULT);
        log.info("订单索引创建确认: {}", createIndexResponse.isAcknowledged());
        return createIndexResponse.isAcknowledged();
    }

    /**
     * 索引订单文档 (插入或更新)
     * @param orderDocument 订单文档对象
     * @return 索引到的文档ID
     * @throws IOException IO异常
     */
    public String indexOrder(OrderDocument orderDocument) throws IOException {
        // 设置同步时间戳
        if (orderDocument.getSyncTimestamp() == null) {
            orderDocument.setSyncTimestamp(System.currentTimeMillis());
        }

        // 构建索引请求
        IndexRequest request = new IndexRequest(INDEX_NAME)
                .id(orderDocument.getId().toString())
                .source(objectMapper.writeValueAsString(orderDocument), XContentType.JSON);

        // 执行索引操作
        IndexResponse response = esClient.index(request, RequestOptions.DEFAULT);
        log.info("订单文档已索引，ID: {}", response.getId());
        return response.getId();
    }

    /**
     * 根据ID获取订单文档
     * @param id 订单ID
     * @return 找到的订单文档对象，如果不存在则返回 null
     * @throws IOException IO异常
     */
    public OrderDocument getOrderById(Long id) throws IOException {
        GetRequest getRequest = new GetRequest(INDEX_NAME, id.toString());
        GetResponse getResponse = esClient.get(getRequest, RequestOptions.DEFAULT);

        if (getResponse.isExists()) {
            Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
            OrderDocument orderDocument = objectMapper.convertValue(sourceAsMap, OrderDocument.class);
            orderDocument.setId(Long.valueOf(getResponse.getId()));
            return orderDocument;
        } else {
            return null;
        }
    }

    /**
     * 根据订单号获取订单文档
     * @param orderNo 订单号
     * @return 找到的订单文档对象，如果不存在则返回 null
     * @throws IOException IO异常
     */
    public OrderDocument getOrderByOrderNo(String orderNo) throws IOException {
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.termQuery("orderNo", orderNo));
        searchSourceBuilder.size(1);
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        if (searchResponse.getHits().getTotalHits().value > 0) {
            try {
                String sourceAsString = searchResponse.getHits().getAt(0).getSourceAsString();
                OrderDocument orderDocument = objectMapper.readValue(sourceAsString, OrderDocument.class);
                orderDocument.setId(Long.valueOf(searchResponse.getHits().getAt(0).getId()));
                return orderDocument;
            } catch (IOException e) {
                log.error("解析订单文档失败", e);
                return null;
            }
        }
        return null;
    }

    /**
     * 搜索订单文档
     * @param userId 用户ID
     * @param status 订单状态
     * @param productName 商品名称关键字
     * @param minAmount 最小金额
     * @param maxAmount 最大金额
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param from 分页起始位置
     * @param size 每页大小
     * @return 匹配的订单文档列表
     * @throws IOException IO异常
     */
    public List<OrderDocument> searchOrders(Long userId, String status, String productName,
                                           BigDecimal minAmount, BigDecimal maxAmount,
                                           LocalDateTime startTime, LocalDateTime endTime,
                                           int from, int size) throws IOException {
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 用户ID过滤
        if (userId != null) {
            boolQuery.filter(QueryBuilders.termQuery("userId", userId));
        }

        // 订单状态过滤
        if (status != null && !status.isEmpty()) {
            boolQuery.filter(QueryBuilders.termQuery("status", status));
        }

        // 商品名称搜索
        if (productName != null && !productName.isEmpty()) {
            boolQuery.must(QueryBuilders.matchQuery("productName", productName));
        }

        // 金额范围过滤
        if (minAmount != null || maxAmount != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("totalAmount")
                    .gte(minAmount)
                    .lte(maxAmount));
        }

        // 时间范围过滤
        if (startTime != null || endTime != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("createTime")
                    .gte(startTime)
                    .lte(endTime));
        }

        searchSourceBuilder.query(boolQuery);
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(size);
        searchSourceBuilder.sort("createTime", SortOrder.DESC);

        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);

        List<OrderDocument> orderDocuments = new ArrayList<>();
        searchResponse.getHits().forEach(hit -> {
            try {
                OrderDocument orderDocument = objectMapper.readValue(hit.getSourceAsString(), OrderDocument.class);
                orderDocument.setId(Long.valueOf(hit.getId()));
                orderDocuments.add(orderDocument);
            } catch (IOException e) {
                log.error("解析订单文档失败", e);
            }
        });
        return orderDocuments;
    }

    /**
     * 更新订单文档的部分字段
     * @param id 订单ID
     * @param updates 要更新的字段及其值
     * @return 更新的文档ID
     * @throws IOException IO异常
     */
    public String updateOrder(Long id, Map<String, Object> updates) throws IOException {
        // 添加更新时间戳
        updates.put("syncTimestamp", System.currentTimeMillis());
        
        UpdateRequest updateRequest = new UpdateRequest(INDEX_NAME, id.toString())
                .doc(updates, XContentType.JSON);

        UpdateResponse updateResponse = esClient.update(updateRequest, RequestOptions.DEFAULT);
        log.info("订单文档已更新，ID: {}, 结果: {}", updateResponse.getId(), updateResponse.getResult());
        return updateResponse.getId();
    }

    /**
     * 根据ID删除订单文档
     * @param id 订单ID
     * @return 是否删除成功
     * @throws IOException IO异常
     */
    public boolean deleteOrder(Long id) throws IOException {
        DeleteRequest deleteRequest = new DeleteRequest(INDEX_NAME, id.toString());
        DeleteResponse deleteResponse = esClient.delete(deleteRequest, RequestOptions.DEFAULT);
        log.info("订单文档已删除，ID: {}, 结果: {}", deleteResponse.getId(), deleteResponse.getResult());
        return deleteResponse.getResult().equals(DeleteResponse.Result.DELETED);
    }

    /**
     * 批量索引订单文档
     * @param orderDocuments 订单文档列表
     * @return 成功索引的文档数量
     * @throws IOException IO异常
     */
    public int batchIndexOrders(List<OrderDocument> orderDocuments) throws IOException {
        int successCount = 0;
        for (OrderDocument orderDocument : orderDocuments) {
            try {
                indexOrder(orderDocument);
                successCount++;
            } catch (IOException e) {
                log.error("批量索引订单失败，订单ID: {}", orderDocument.getId(), e);
            }
        }
        log.info("批量索引订单完成，成功: {}, 总数: {}", successCount, orderDocuments.size());
        return successCount;
    }

    /**
     * 删除订单索引
     * @return 是否删除成功
     * @throws IOException IO异常
     */
    public boolean deleteOrderIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest(INDEX_NAME);
        AcknowledgedResponse deleteResponse = esClient.indices().delete(request, RequestOptions.DEFAULT);
        log.info("订单索引删除确认: {}", deleteResponse.isAcknowledged());
        return deleteResponse.isAcknowledged();
    }
}